{"cells": [{"cell_type": "markdown", "id": "3f40677e", "metadata": {}, "source": ["# High-Frequency Grid Trading - Comparison Across Other Exchanges\n", "\n", "So far, we have explored examples in Binance Futures. In this section, we demonstrate how results can vary for the same pair and parameter set across different exchanges, due to differences in order flow.\n", "\n", "Since each exchange may have its own distinct order flow, performance can differ significantly. This also highlights the need to explore alternative parameter sets to optimize performance for each specific exchange. By doing so, you can extend your analysis to other platforms such as OKX, Hyperliquid, and more."], "execution_count": 0}, {"cell_type": "code", "execution_count": 1, "id": "0c8ef816-5277-45f8-a46c-cdf43ae16989", "metadata": {}, "outputs": [], "source": ["import json\n", "import datetime\n", "import itertools\n", "\n", "from multiprocessing import Pool\n", "\n", "import polars as pl\n", "\n", "import numpy as np\n", "\n", "from numba import njit, uint64, float64\n", "from numba.typed import Dict\n", "\n", "from matplotlib import pyplot as plt\n", "\n", "from hftbacktest import BUY, SELL, GTX, LIMIT, BUY_EVENT, SELL_EVENT\n", "from hftbacktest import BacktestAsset, ROIVectorMarketDepthBacktest, Recorder\n", "from hftbacktest.stats import LinearAssetRecord\n", "\n", "@njit\n", "def gridtrading(hbt, recorder, relative_half_spread, relative_grid_interval, min_grid_step, grid_num, skew, order_qty):\n", " asset_no = 0\n", " tick_size = hbt.depth(asset_no).tick_size\n", " max_position = grid_num * order_qty\n", " \n", " # Running interval in nanoseconds.\n", " while hbt.elapse(100_000_000) == 0:\n", " # Clears cancelled, filled or expired orders. \n", " hbt.clear_inactive_orders(asset_no)\n", "\n", " depth = hbt.depth(asset_no)\n", " position = hbt.position(asset_no)\n", " orders = hbt.orders(asset_no)\n", "\n", " best_bid = depth.best_bid\n", " best_ask = depth.best_ask\n", " \n", " mid_price = (best_bid + best_ask) / 2.0\n", "\n", " normalized_position = position / order_qty\n", "\n", " relative_bid_depth = relative_half_spread + skew * normalized_position\n", " relative_ask_depth = relative_half_spread - skew * normalized_position\n", "\n", " # Please see Market Making with Alpha example series.\n", " # https://hftbacktest.readthedocs.io/en/latest/tutorials/Market%20Making%20with%20Alpha%20-%20Order%20Book%20Imbalance.html\n", " # https://hftbacktest.readthedocs.io/en/latest/tutorials/Market%20Making%20with%20Alpha%20-%20Basis.html\n", " # https://hftbacktest.readthedocs.io/en/latest/tutorials/Market%20Making%20with%20Alpha%20-%20APT.html\n", " #\n", " # Without alpha, this relies heavily on rebates combined with short-term mean reversion to the current price \u2014 \n", " # a behavior that has been observed to be particularly strong in altcoins.\n", " alpha = 0.0\n", " forecast_mid_price = mid_price + alpha\n", "\n", " # Since our price is skewed, it may cross the spread. To ensure market making and avoid crossing the spread, \n", " # limit the price to the best bid and best ask.\n", " bid_price = np.minimum(forecast_mid_price * (1.0 - relative_bid_depth), best_bid)\n", " ask_price = np.maximum(forecast_mid_price * (1.0 + relative_ask_depth), best_ask)\n", "\n", " # min_grid_step enforces grid interval changes to be no less than min_grid_step, which\n", " # stabilizes the grid_interval and keeps the orders on the grid more stable.\n", " grid_interval = max(np.round(forecast_mid_price * relative_grid_interval / min_grid_step) * min_grid_step, min_grid_step)\n", "\n", " # Aligns the prices to the grid.\n", " bid_price = np.floor(bid_price / grid_interval) * grid_interval\n", " ask_price = np.ceil(ask_price / grid_interval) * grid_interval\n", " \n", " #--------------------------------------------------------\n", " # Updates quotes.\n", " \n", " # Creates a new grid for buy orders.\n", " new_bid_orders = Dict.empty(np.uint64, np.float64)\n", " if position < max_position and np.isfinite(bid_price): # position * mid_price < max_notional_position\n", " for i in range(grid_num):\n", " bid_price_tick = round(bid_price / tick_size)\n", " \n", " # order price in tick is used as order id.\n", " new_bid_orders[uint64(bid_price_tick)] = bid_price\n", " \n", " bid_price -= grid_interval\n", "\n", " # Creates a new grid for sell orders.\n", " new_ask_orders = Dict.empty(np.uint64, np.float64)\n", " if position > -max_position and np.isfinite(ask_price): # position * mid_price > -max_notional_position\n", " for i in range(grid_num):\n", " ask_price_tick = round(ask_price / tick_size)\n", " \n", " # order price in tick is used as order id.\n", " new_ask_orders[uint64(ask_price_tick)] = ask_price\n", "\n", " ask_price += grid_interval\n", " \n", " order_values = orders.values();\n", " while order_values.has_next():\n", " order = order_values.get()\n", " # Cancels if a working order is not in the new grid.\n", " if order.cancellable:\n", " if (\n", " (order.side == BUY and order.order_id not in new_bid_orders)\n", " or (order.side == SELL and order.order_id not in new_ask_orders)\n", " ):\n", " hbt.cancel(asset_no, order.order_id, False)\n", " \n", " for order_id, order_price in new_bid_orders.items():\n", " # Posts a new buy order if there is no working order at the price on the new grid.\n", " if order_id not in orders:\n", " hbt.submit_buy_order(asset_no, order_id, order_price, order_qty, GTX, LIMIT, False)\n", " \n", " for order_id, order_price in new_ask_orders.items():\n", " # Posts a new sell order if there is no working order at the price on the new grid.\n", " if order_id not in orders:\n", " hbt.submit_sell_order(asset_no, order_id, order_price, order_qty, GTX, LIMIT, False)\n", " \n", " # Records the current state for stat calculation.\n", " recorder.record(hbt)\n", " return True"]}, {"cell_type": "markdown", "id": "4dc02bfd-1dd2-475d-a029-8d9e2ed5ea56", "metadata": {}, "source": ["## Bybit\n", "\n", "